Goal

Analyze the evolution of sequence features of the XP_028889033 homologs within C. auris species. In particular, we are interested in intra-species variation in copy number, NTD protein sequence evolutionary rates, stalk repeat numbers and sequences.

Homologs identification

Homologs of the PF11765 domain containing proteins were identified in the five strains of C. auris used in Muñoz et al. 2018 Nat. Genet. Homologs from C. pseudohaemulonis and C. haemuloni were added to help provide the evolutionary context, e.g. timing of gene duplication and sequence evolution both within and between closely related species. Finally, two homologs from the outrgroup species D. hansenii were added to root the gene tree. A third D. hansenii sequencing with the PF11765 domain was not included as it belong to the Clavispora/Candida duplicate 2 branch, which didn’t include any C. auris sequences.

Evolution (duplications and losses)

Gene tree

The gene tree inferred based on the PF11765 domain in each sequence is presented below:

gene tree Figure 1. RAxML inferred gene tree for Hyr/Iff-Like (HIL) family members in C. auris, two MDR clade species C. pseudohaemulonis and C. haemuloni, as well as an outgroup D. hansenii. The branch thickness is shown proportional to the value of the rapid bootstrapping value. The tree is manually rooted on the two D. hansenii sequences. The root choice is based on the gene tree including homologs from across the Ascomycetes. The short terminal branch lengths among the C. auris strains indicate that there had been little divergence in the PF11765 domain in these sequences. Lastly, the colors of the leaf node names for the C. auris strains are based on Muñoz et al. 2018 Nat. Genet.

Reconciliation and rearrangement

To infer the timing of gene duplication and loss events, the gene tree is reconciled with the species tree in Notung 2.9. Rearrangement of the reconciled gene tree was performed in the same software, allowing for swapping of branches with rapid bootstrapping values lower than 90%. The rearranged tree has a total of 15 duplication and 13 losses. Note that the clade I strain 6684 appeared to have experienced several losses, but this is very likely due to the relatively poor assembly status of the strain, not real evolutionary losses.

Evolution of sequence features

Build datasets

  1. Sequence IDs, species and strain information.

  2. Adhesin prediction results

    FungalRV threshold: 0.51; FaaPred using ACHM model with the recommended -0.8 threshold.

  3. GPI-anchor prediction (including signal peptide)

    GPI-anchored proteins are characterized by an N-terminal signal peptide, which would direct the protein to the secretary pathway, and a C-terminal GPI-anchor peptide, which would be cleaved and replaced by the GPI-anchor, allowing the protein to be tethered to the cell wall. For signal peptide, I used SignalP server. Its latest version is 5.0. But I also ran the sequences through their 4.1 version, with two settings. The results of the latter two are almost identical, except for one sequence “XP_024711350.1”, which is only included in the sensitive version, and has a probability lower than 0.5. For GPI-anchor prediction, I used the PredGPI server. For signal peptide prediction, I used the SignalP 5.0 server

sps.list <- c("Cauris","Cpseudohaemulonis","Chaemuloni","Dhansenii")
seqInfo <- read_tsv("output/seq-feature/cauris-renamed-seqinfo.tsv", comment = "#", col_types = "cccci") %>% 
  mutate(species_id = factor(species, levels = sps.list), species = NULL)

Adhesin prediction

frv.th = 0.511 # recommended FungalRV score threshold
frv <- read_tsv("output/seq-feature/cauris-renamed-fungalrv.txt", skip = 3, col_names = c("name","frv.score"), col_types = "cd") %>% 
  mutate(name = str_sub(name, 2), frv.pred = frv.score > frv.th)
faa <- read_tsv("output/seq-feature/cauris-renamed-faapred.txt", col_names = c("name","faa.score","faa.pred"), col_types = "cdc") %>% 
  mutate(faa.pred = ifelse(faa.pred == "Adhesin", TRUE, FALSE))
if("frv.score" %in% names(seqInfo))
  seqInfo <- select(seqInfo, -frv.score, -frv.pred, -faa.score, -faa.pred)
seqInfo <- seqInfo %>% left_join(frv) %>% left_join(faa)
Joining, by = "name"
Joining, by = "name"
seqInfo %>% 
  group_by(species_id, strain) %>% 
  summarize(n = n(), fungalRV = sum(frv.score > 0.511), faapred = sum(faa.pred, na.rm = T), 
            both = sum(frv.score > 0.511 & faa.pred))
`summarise()` has grouped output by 'species_id'. You can override using the `.groups` argument.

SignalP and GPI prediction

# Signal peptide
gff.names <- c("id", "source", "name", "start", "end", "prob", "na1", "na2", "na3")
signalp5 <- read_tsv("output/seq-feature/cauris-renamed-signalp5.gff3", comment = "#", col_names = gff.names, col_types = "ccciidccc")

if("signalp" %in% names(seqInfo))
  seqInfo <- select(seqInfo, -signalp)

seqInfo <- left_join(seqInfo, select(signalp5, name = id, prob), by = c("name" = "name")) %>% 
  mutate(signalp = !is.na(prob)) %>% select(-prob)
tmp <- read_delim("output/seq-feature/cauris-renamed-predgpi.txt", delim = "|", col_names = c("name","fp","omega"))

── Column specification ───────────────────────────────────────────────────────────────────────────────────
cols(
  name = col_character(),
  fp = col_character(),
  omega = col_character()
)
pred.gpi <- tmp %>%  
  mutate(name = str_sub(name, 2, -2), # remove > and the trailing space
         fp = as.numeric(str_sub(fp, 9, -2)), # extract the numeric part
         is.gpi = fp <= 0.01,    # based on the cutoff of the PredGPI server (prob < 99% -> not GPI-anchored)
         omega = str_sub(omega, 8),
         cleaveRes = str_sub(omega, 1, 1),
         cleavePos = as.integer(str_sub(omega, 3)),
         ) %>% 
  left_join(select(seqInfo, name, length), by = c("name" = "name"))

# remove the column if it already exists
if("pred.gpi" %in% names(seqInfo))
  seqInfo <- select(seqInfo, -pred.gpi)
seqInfo <- left_join(seqInfo, select(pred.gpi, name, pred.gpi = is.gpi), by = c("name"="name"))

seqInfo %>% 
  group_by(species_id, strain) %>% 
  summarize(Total = n(), SignalP = sum(signalp), GPI_Pred = sum(pred.gpi), Both = sum(signalp & pred.gpi))
`summarise()` has grouped output by 'species_id'. You can override using the `.groups` argument.
write_tsv(seqInfo, "output/seq-feature/R-seqinfo-table.tsv", col_names = TRUE)

Domain architecture

The goal is to produce a cartoon-like plot for each homolog outlining their main features, such as the locations of the PFam domains (mainly the Hyp_reg_CWP), locations of the signal peptide and GPI-anchor, distribution of TANGO sequences. Note that all these features can be represented as a range with associated metadata. So the first step is to collect the coordinates of the features

# GPI-anchor
# use pred.gpi
# Pfam domains
pfam <- read_tsv("output/seq-feature/cauris-renamed-hmmer-scan.txt", col_types = "ciiiicciiidddiic")
# save feature file for Jalview examination
# pfam %>% filter(grepl("XP_028889033",seq_id)) %>% select(hmm_name, seq_id, envelope_start, envelope_end) %>% mutate(featuretype = "domain") %>% write_tsv("XP_028889033_features.jalview")
# I manually edited the feature file, so I commented out the line above to avoid accidentally 
# overwriting my own edits

# feature set
# structure: id  feature  start  end
feature <- bind_rows(
  seqInfo %>% mutate(type = "entire protein", start = 1) %>% select(id = name, type, start, end = length),
  pfam %>% select(id = seq_id, type = hmm_name, start = envelope_start, end = envelope_end),
  # extend the signal peptide segment by 10 amino acids to make it more visible
  signalp5 %>% mutate(type = "SignalP", end = end + 10) %>% select(id, type, start = start, end),
  # extend the GPI-anchor C-terminus segment by 20 amino acids to make it more visible
  pred.gpi %>% filter(is.gpi) %>% mutate(type = "GPI-anchor", start = cleavePos-10) %>% 
    select(id = name, type, start, end = length)
)
feature$type = ordered(feature$type, levels = c("entire protein", "Hyphal_reg_CWP", "Asp", "Hyr1", "SignalP", "GPI-anchor"))
feature.colors <- c("grey", "#1f78b4", "#b2df8a", "#ff7f00", "#e31a1c", "#6a3d9a")
# in order to plot properties of the sequences in an order that is consistent with the sequences' position in the gene tree
genetreeOrder <- scan("output/seq-feature/cauris-reorder-by-gene-tree.txt", what = "character")
Read 55 items
genetreeColor <- tibble(name = genetreeOrder) %>% 
  mutate(color = case_when(
    grepl("haemuloni", name) ~ "#2596be70",
    grepl("6684", name) ~ "#0e8c07",
    grepl("B8441", name) ~ "#0e8c07",
    grepl("B11220", name) ~ "#780a76",
    grepl("B11221", name) ~ "#0409fb",
    grepl("B11243", name) ~ "#ff4c00",
    TRUE ~ "#000000"
    ))
feature$id <- ordered(feature$id, levels = rev(genetreeOrder))
write_tsv(feature, file = "output/seq-feature/R-feature-table.tsv", col_names = TRUE)
p <- ggplot(feature, aes(x = id, y = start)) + 
  geom_segment(aes(xend = id, yend = end, color = type), size = 2)
p + coord_flip() + theme_classic() + scale_color_manual(values = feature.colors) +
  theme(axis.text.y = element_text(size = 6, colour = rev(genetreeColor$color)),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(), axis.ticks.x = element_blank(),
        legend.position = c(0.8,0.8),
        panel.background = element_rect(fill = alpha("lightblue",0.5))) +
  ylim(1, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Domain / Feature") + 
  ggtitle("Domain architecture")

ggsave("output/figure/20210425-homologs-domains-schematics.png", bg = "transparent", width = 7, height = 6)

TANGO prediction of \(\beta\)-aggregation prone sequences

The amyloid-like \(\beta\)-aggregation prone sequences have the ability to mediate self-aggregation, which boosts the local concentration of the adhesin molecules on the cell-surface. Similar to the S/T frequency above, we would like to use the output from the prediction algorithm, TANGO, to visulize the distribution of such sequence motifs along the length of the XP_028889033 homolog sequences.

Parse tango output

extract_tango <- function(tango_output, agg_threshold = 5, required_in_serial = 5) {
    require(tidyverse)
    tmp <- read_tsv(file = tango_output, col_types = "icddddd") %>% 
        # a boolean vector for residues above threshold
        mutate(pass = Aggregation > agg_threshold)
    pass.rle <- rle(tmp$pass) # this creates a run length encoding that will be useful for identifying the sub-sequences in a run longer than certain length
    # --- Explanation ---
    # this rle object is at the core of this function
    # an example of the rle looks like
    #   lengths: int[1:10] 5 19 20 8 1 5 19 6 181 18
    #   values: logi[1:10] F T  F  T F T F  T F   T
    #   note that by definition the values will always be T/F interdigitated
    # our goal is to identify the sub-sequences that is defined as a stretch of 
    # n consecutive positions with a score greater than the cutoff and record the
    # sub-sequence, its length, start and end position, 90% quantile of the score
    # --- End of explanation ---
    # 1. assigns a unique id for each run of events
    tmp$group <- rep(1:length(pass.rle$lengths), times = pass.rle$lengths)
    # 2. extract the subsequences
    agg.seq <- tmp %>% 
        filter(pass) %>% # drop residues not predicted to have aggregation potential
        group_by(group) %>% # cluster by the runs
        summarize(seq = paste0(aa, collapse = ""),
                  start = min(res), end = max(res), length = n(),
                  median = median(Aggregation),
                  q90 = quantile(Aggregation, probs = 0.9),
                  ivt = sum(aa %in% c("I","V","T")) / length(aa),
                  .groups = "drop") %>% 
        mutate(interval = start - lag(end) - 1) %>% 
        filter(length >= required_in_serial) %>% 
        select(-group)
    return(agg.seq)
}
tango.output.files <- list.files(path = "output/tango", pattern = ".txt|.txt.gz", full.names = T)
# the read_csv() function used in the custom function can automatically decompress gzipped files
tango.res <- lapply(tango.output.files, extract_tango)
names(tango.res) <- gsub(".txt|.txt.gz", "", basename(tango.output.files))
# to add species information
tango.res.df <- bind_rows(tango.res, .id = "id") %>%
  mutate(id = gsub("_B[0-9]+$", "", id))
# save the tango output
write_tsv(tango.res.df, "output/tango/tango_summary_table.tsv.gz")
# mutate(species = str_split(id, "_(?!.*_)", simplify = TRUE)[,2]) 
# extract the species names
# credit: https://stackoverflow.com/questions/20454768/how-to-split-a-string-from-right-to-left-like-pythons-rsplit
# the split pattern is equivalent to the rsplit() function in python

Plotting TANGO hits

# add species and strain information for plotting
tango <- left_join(select(seqInfo, name, id, species_id, strain),  tango.res.df, by = c("id" = "id"))
# reorder the sequences for plotting
tango$name <- ordered(tango$name, levels = rev(genetreeOrder))
# plot
p1 <- ggplot(filter(feature, type == "entire protein"), aes(x = id, y = start)) + 
  geom_segment(aes(xend = id, yend = end), size = 2, color = "grey40")
p2 <- geom_segment(data = tango, aes(x = name, xend = name,  y = ifelse(start-4 >= 0, start-4, 0), yend = end + 4, color = median), size = 2)
p3 <- geom_segment(data = filter(feature, type == "Hyphal_reg_CWP"), aes(x = id, y = start, xend = id, yend = end), size = 2, color = "#1f78b4")
p1 + p2 + p3 + coord_flip() + theme_classic() + 
  scale_color_distiller(type = "seq", palette = 17, direction = 1) +
  theme(axis.text.y = element_text(size = 6, colour = rev(genetreeColor$color)),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(), axis.ticks.x = element_blank(),
        legend.position = c(0.8,0.8),
        panel.background = element_rect(fill = alpha("lightblue",0.5))) +
  ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") + 
  ggtitle("TANGO hits with Hyphal_reg_CWP domain masked")

ggsave("output/figure/20210425-tango-score-segment.png", width = 7, height = 6)

Tandem repeat structures

The non-NTD portion of the proteins evolve rapidly and many of them contain tandem repeats. Therefore, characterizing and visualizing the type, number and spatial distribution of the tandem repeats serve to highlight the differences in the non-NTD part of the proteins in this family.

To identify and group tandem repeats, I used XSTREAM with the following parameters java -Xmx1000m -Xms1000m -jar ~/sw/XSTREAM/xstream.jar $in -i.7 -I.7 -g3 -e2 -L15 -z -G -O. The parameters were chosen to identify degenerate tandem repeats that occur at least two times and must be a minimum length of 5 a.a. or longer and the minimum length of a tandem repeat domain (=period x copy #) must be greater than 15 a.a. Please see script/xstream.sh for explanation of the parameters.

tandem <- read_tsv("output/tandem-repeats/XSTREAM_cauris_outgr_i0.7_g3_m5_L15_chart.tsv", 
                   col_types = "ciiifidcccd") %>% 
  rename(name = identifier) %>% 
  mutate(name = ordered(name, levels = rev(genetreeOrder)))
# now let's create a tibble for plotting, which would contain each instance of the tandem repeat on a separate row
tandem.div <- tandem %>% 
  rowwise(name) %>% 
  summarize(div = list(c(seq(from = start, to = end, by = period), end)), .groups = "drop") %>% 
  unnest(div)
# plot
require(RColorBrewer)
n.col = nlevels(tandem$type)
tr.col <- colorRampPalette(brewer.pal(12, "Paired")[3:12])(n.col)
p1 <- ggplot(filter(feature, type == "entire protein"), aes(x = id, y = start)) + 
  geom_segment(aes(xend = id, yend = end), size = 2.5, color = "grey40")
p2 <- geom_segment(data = tandem, aes(x = name, xend = name,  y = start, yend = end, color = type, text = consensus_nogap), size = 2.5, alpha = 0.9)
p3 <- geom_segment(data = tandem.div, aes(x = name, xend = name, y = div, yend = div + 2), size = 2.5)
p4 <- geom_segment(data = filter(feature, type == "Hyphal_reg_CWP"), aes(x = id, y = start, xend = id, yend = end), color = "#1f78b4", size = 2.5)
p <- p1 + p2 + p3 + p4 + coord_flip() + theme_classic() + 
  scale_color_manual(values = tr.col) +
  theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(), axis.ticks.x = element_blank(),
        legend.position = "none",
        panel.background = element_rect(fill = alpha("lightblue",0.5))) +
  ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") + 
  ggtitle("Tandem repeat domains with Hyphal_reg_CWP domain shown")
p

ggsave("output/figure/20210506-tandem-repeats.png", width = 7, height = 6)

Note Blue boxes indicate the PF11765 domains while all other non-grey boxes indicate XSTREAM-determined tandem repeat domains. Colors are used to group highly similar tandem repeats. The black thin lines demarcate adjacent tandem repeat units. The table below shows the copy number, period and consensus sequence for each tandem domain organized by the host sequences.

DT::datatable(
  tandem %>% 
    rename(seqL = seqLength, err = consensus_error, seq = consensus_nogap) %>% 
    select(-seqAlign, -type, -consensus_gap, -seq, seq) %>% 
    arrange(desc(name)),
  fillContainer = FALSE, options = list(pageLength = 10)
)
# combine sequence features with tandem repeats
tr.feature <- rbind(
  feature %>% 
    filter(type %in% c("entire protein", "Hyphal_reg_CWP"), ) %>%
    mutate(name = id, tip = ifelse(type == "entire protein", as.character(name), "PF11765")) %>% 
    select(name, type, start, end, tip),
  tandem %>% mutate(type = paste0("tandem", type)) %>% select(name, type, start, end, tip = consensus_nogap)
) %>% mutate(type = droplevels(type))
# plot
require(RColorBrewer)
require(plotly)
n.col = nlevels(tr.feature$type)
tr.col <- c("grey40", "#1f78b4", colorRampPalette(brewer.pal(12, "Paired")[3:12])(n.col-2))
p1 <- ggplot(tr.feature, aes(x = name, y = start, xend = name, yend = end, color = type, text = tip)) + 
  geom_segment(size = 2)
p2 <- geom_segment(size = 2, alpha = 0.9)
p <- p1 + p2 + coord_flip() + theme_classic() + 
  scale_color_manual(values = tr.col) +
  theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(), axis.ticks.x = element_blank(),
        legend.position = "none",
        panel.background = element_rect(fill = alpha("lightblue",0.5))) +
  ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") + 
  ggtitle("Tandem repeat domains with Hyphal_reg_CWP domain shown")
ggplotly(p, tooltip = "text")
LS0tCnRpdGxlOiAiQW5hbHl6ZSBYUF8wMjg4ODkwMzMgaG9tb2xvZ3MgaW4gQy4gYXVyaXMgc3RyYWlucyIKYXV0aG9yOiAiQmluIEhlIgpkYXRlOiAiMDQvMjMvMjAyMSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKYGBge3IgbG9hZF9saWJyYXJpZXMsIGVjaG8gPSBGQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkodGlkeXZlcnNlKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY293cGxvdCkpCmBgYAoKIyMgR29hbAoKQW5hbHl6ZSB0aGUgZXZvbHV0aW9uIG9mIHNlcXVlbmNlIGZlYXR1cmVzIG9mIHRoZSBYUF8wMjg4ODkwMzMgaG9tb2xvZ3Mgd2l0aGluIF9DLiBhdXJpc18gc3BlY2llcy4gSW4gcGFydGljdWxhciwgd2UgYXJlIGludGVyZXN0ZWQgaW4gaW50cmEtc3BlY2llcyB2YXJpYXRpb24gaW4gY29weSBudW1iZXIsIE5URCBwcm90ZWluIHNlcXVlbmNlIGV2b2x1dGlvbmFyeSByYXRlcywgc3RhbGsgcmVwZWF0IG51bWJlcnMgYW5kIHNlcXVlbmNlcy4KCiMjIEhvbW9sb2dzIGlkZW50aWZpY2F0aW9uCkhvbW9sb2dzIG9mIHRoZSBQRjExNzY1IGRvbWFpbiBjb250YWluaW5nIHByb3RlaW5zIHdlcmUgaWRlbnRpZmllZCBpbiB0aGUgZml2ZSBzdHJhaW5zIG9mIF9DLiBhdXJpc18gdXNlZCBpbiBNdcOxb3ogX2V0IGFsLl8gMjAxOCBOYXQuIEdlbmV0LiBIb21vbG9ncyBmcm9tIF9DLiBwc2V1ZG9oYWVtdWxvbmlzXyBhbmQgX0MuIGhhZW11bG9uaV8gd2VyZSBhZGRlZCB0byBoZWxwIHByb3ZpZGUgdGhlIGV2b2x1dGlvbmFyeSBjb250ZXh0LCBlLmcuIHRpbWluZyBvZiBnZW5lIGR1cGxpY2F0aW9uIGFuZCBzZXF1ZW5jZSBldm9sdXRpb24gYm90aCB3aXRoaW4gYW5kIGJldHdlZW4gY2xvc2VseSByZWxhdGVkIHNwZWNpZXMuIEZpbmFsbHksIHR3byBob21vbG9ncyBmcm9tIHRoZSBvdXRyZ3JvdXAgc3BlY2llcyBfRC4gaGFuc2VuaWlfIHdlcmUgYWRkZWQgdG8gcm9vdCB0aGUgZ2VuZSB0cmVlLiBBIHRoaXJkIF9ELiBoYW5zZW5paV8gc2VxdWVuY2luZyB3aXRoIHRoZSBQRjExNzY1IGRvbWFpbiB3YXMgbm90IGluY2x1ZGVkIGFzIGl0IGJlbG9uZyB0byB0aGUgQ2xhdmlzcG9yYS9DYW5kaWRhIGR1cGxpY2F0ZSAyIGJyYW5jaCwgd2hpY2ggZGlkbid0IGluY2x1ZGUgYW55IF9DLiBhdXJpc18gc2VxdWVuY2VzLgoKIyMgRXZvbHV0aW9uIChkdXBsaWNhdGlvbnMgYW5kIGxvc3NlcykKIyMjIEdlbmUgdHJlZQpUaGUgZ2VuZSB0cmVlIGluZmVycmVkIGJhc2VkIG9uIHRoZSBQRjExNzY1IGRvbWFpbiBpbiBlYWNoIHNlcXVlbmNlIGlzIHByZXNlbnRlZCBiZWxvdzoKCiFbZ2VuZSB0cmVlXShvdXRwdXQvZ2VuZS10cmVlL3dpdGgtb3V0Z3JvdXAvUkF4TUxfYmlwYXJ0aXRpb25zLmNsdXN0YWxvXzQ5MjE4NjIucG5nKQoqKkZpZ3VyZSAxLiBSQXhNTCBpbmZlcnJlZCBnZW5lIHRyZWUgZm9yIEh5ci9JZmYtTGlrZSAoSElMKSBmYW1pbHkgbWVtYmVycyBpbiBfQy4gYXVyaXNfLCB0d28gTURSIGNsYWRlIHNwZWNpZXMgX0MuIHBzZXVkb2hhZW11bG9uaXNfIGFuZCBfQy4gaGFlbXVsb25pXywgYXMgd2VsbCBhcyBhbiBvdXRncm91cCBfRC4gaGFuc2VuaWlfLioqIFRoZSBicmFuY2ggdGhpY2tuZXNzIGlzIHNob3duIHByb3BvcnRpb25hbCB0byB0aGUgdmFsdWUgb2YgdGhlIHJhcGlkIGJvb3RzdHJhcHBpbmcgdmFsdWUuIFRoZSB0cmVlIGlzIG1hbnVhbGx5IHJvb3RlZCBvbiB0aGUgdHdvIF9ELiBoYW5zZW5paV8gc2VxdWVuY2VzLiBUaGUgcm9vdCBjaG9pY2UgaXMgYmFzZWQgb24gdGhlIGdlbmUgdHJlZSBpbmNsdWRpbmcgaG9tb2xvZ3MgZnJvbSBhY3Jvc3MgdGhlIEFzY29teWNldGVzLiBUaGUgc2hvcnQgdGVybWluYWwgYnJhbmNoIGxlbmd0aHMgYW1vbmcgdGhlIF9DLiBhdXJpc18gc3RyYWlucyBpbmRpY2F0ZSB0aGF0IHRoZXJlIGhhZCBiZWVuIGxpdHRsZSBkaXZlcmdlbmNlIGluIHRoZSBQRjExNzY1IGRvbWFpbiBpbiB0aGVzZSBzZXF1ZW5jZXMuIExhc3RseSwgdGhlIGNvbG9ycyBvZiB0aGUgbGVhZiBub2RlIG5hbWVzIGZvciB0aGUgX0MuIGF1cmlzXyBzdHJhaW5zIGFyZSBiYXNlZCBvbiBNdcOxb3ogX2V0IGFsLl8gMjAxOCBOYXQuIEdlbmV0LgoKIyMjIFJlY29uY2lsaWF0aW9uIGFuZCByZWFycmFuZ2VtZW50ClRvIGluZmVyIHRoZSB0aW1pbmcgb2YgZ2VuZSBkdXBsaWNhdGlvbiBhbmQgbG9zcyBldmVudHMsIHRoZSBnZW5lIHRyZWUgaXMgcmVjb25jaWxlZCB3aXRoIHRoZSBzcGVjaWVzIHRyZWUgaW4gTm90dW5nIDIuOS4gUmVhcnJhbmdlbWVudCBvZiB0aGUgcmVjb25jaWxlZCBnZW5lIHRyZWUgd2FzIHBlcmZvcm1lZCBpbiB0aGUgc2FtZSBzb2Z0d2FyZSwgYWxsb3dpbmcgZm9yIHN3YXBwaW5nIG9mIGJyYW5jaGVzIHdpdGggcmFwaWQgYm9vdHN0cmFwcGluZyB2YWx1ZXMgbG93ZXIgdGhhbiAqKjkwJSoqLiBUaGUgcmVhcnJhbmdlZCB0cmVlIGhhcyBhIHRvdGFsIG9mICoqMTUqKiBkdXBsaWNhdGlvbiBhbmQgKioxMyoqIGxvc3Nlcy4gTm90ZSB0aGF0IHRoZSBjbGFkZSBJIHN0cmFpbiA2Njg0IGFwcGVhcmVkIHRvIGhhdmUgZXhwZXJpZW5jZWQgc2V2ZXJhbCBsb3NzZXMsIGJ1dCB0aGlzIGlzIHZlcnkgbGlrZWx5IGR1ZSB0byB0aGUgcmVsYXRpdmVseSBwb29yIGFzc2VtYmx5IHN0YXR1cyBvZiB0aGUgc3RyYWluLCBub3QgcmVhbCBldm9sdXRpb25hcnkgbG9zc2VzLgoKIyMgRXZvbHV0aW9uIG9mIHNlcXVlbmNlIGZlYXR1cmVzCiMjIyBCdWlsZCBkYXRhc2V0cwoxLiBTZXF1ZW5jZSBJRHMsIHNwZWNpZXMgYW5kIHN0cmFpbiBpbmZvcm1hdGlvbi4KMS4gQWRoZXNpbiBwcmVkaWN0aW9uIHJlc3VsdHMKCiAgICBGdW5nYWxSViB0aHJlc2hvbGQ6IDAuNTE7IEZhYVByZWQgdXNpbmcgQUNITSBtb2RlbCB3aXRoIHRoZSByZWNvbW1lbmRlZCAtMC44IHRocmVzaG9sZC4KICAgIAoxLiBHUEktYW5jaG9yIHByZWRpY3Rpb24gKGluY2x1ZGluZyBzaWduYWwgcGVwdGlkZSkKCiAgICBHUEktYW5jaG9yZWQgcHJvdGVpbnMgYXJlIGNoYXJhY3Rlcml6ZWQgYnkgYW4gTi10ZXJtaW5hbCBzaWduYWwgcGVwdGlkZSwgd2hpY2ggd291bGQgZGlyZWN0IHRoZSBwcm90ZWluIHRvIHRoZSBzZWNyZXRhcnkgcGF0aHdheSwgYW5kIGEgQy10ZXJtaW5hbCBHUEktYW5jaG9yIHBlcHRpZGUsIHdoaWNoIHdvdWxkIGJlIGNsZWF2ZWQgYW5kIHJlcGxhY2VkIGJ5IHRoZSBHUEktYW5jaG9yLCBhbGxvd2luZyB0aGUgcHJvdGVpbiB0byBiZSB0ZXRoZXJlZCB0byB0aGUgY2VsbCB3YWxsLiBGb3Igc2lnbmFsIHBlcHRpZGUsIEkgdXNlZCBTaWduYWxQIHNlcnZlci4gSXRzIGxhdGVzdCB2ZXJzaW9uIGlzIDUuMC4gQnV0IEkgYWxzbyByYW4gdGhlIHNlcXVlbmNlcyB0aHJvdWdoIHRoZWlyIDQuMSB2ZXJzaW9uLCB3aXRoIHR3byBzZXR0aW5ncy4gVGhlIHJlc3VsdHMgb2YgdGhlIGxhdHRlciB0d28gYXJlIGFsbW9zdCBpZGVudGljYWwsIGV4Y2VwdCBmb3Igb25lIHNlcXVlbmNlICJYUF8wMjQ3MTEzNTAuMSIsIHdoaWNoIGlzIG9ubHkgaW5jbHVkZWQgaW4gdGhlIHNlbnNpdGl2ZSB2ZXJzaW9uLCBhbmQgaGFzIGEgcHJvYmFiaWxpdHkgbG93ZXIgdGhhbiAwLjUuCiAgICBGb3IgR1BJLWFuY2hvciBwcmVkaWN0aW9uLCBJIHVzZWQgdGhlIFtQcmVkR1BJIHNlcnZlcl0oaHR0cDovL2dwY3IuYmlvY29tcC51bmliby5pdC9wcmVkZ3BpLykuCiAgICBGb3Igc2lnbmFsIHBlcHRpZGUgcHJlZGljdGlvbiwgSSB1c2VkIHRoZSBbU2lnbmFsUCA1LjAgc2VydmVyXShodHRwOi8vd3d3LmNicy5kdHUuZGsvc2VydmljZXMvU2lnbmFsUC8pCgpgYGB7ciBsb2FkX3NlcV9pbmZvfQpzcHMubGlzdCA8LSBjKCJDYXVyaXMiLCJDcHNldWRvaGFlbXVsb25pcyIsIkNoYWVtdWxvbmkiLCJEaGFuc2VuaWkiKQpzZXFJbmZvIDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtc2VxaW5mby50c3YiLCBjb21tZW50ID0gIiMiLCBjb2xfdHlwZXMgPSAiY2NjY2kiKSAlPiUgCiAgbXV0YXRlKHNwZWNpZXNfaWQgPSBmYWN0b3Ioc3BlY2llcywgbGV2ZWxzID0gc3BzLmxpc3QpLCBzcGVjaWVzID0gTlVMTCkKYGBgCgojIyMgQWRoZXNpbiBwcmVkaWN0aW9uCmBgYHtyIGFkaGVzaW5fcHJlZGljdGlvbn0KZnJ2LnRoID0gMC41MTEgIyByZWNvbW1lbmRlZCBGdW5nYWxSViBzY29yZSB0aHJlc2hvbGQKZnJ2IDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtZnVuZ2FscnYudHh0Iiwgc2tpcCA9IDMsIGNvbF9uYW1lcyA9IGMoIm5hbWUiLCJmcnYuc2NvcmUiKSwgY29sX3R5cGVzID0gImNkIikgJT4lIAogIG11dGF0ZShuYW1lID0gc3RyX3N1YihuYW1lLCAyKSwgZnJ2LnByZWQgPSBmcnYuc2NvcmUgPiBmcnYudGgpCmZhYSA8LSByZWFkX3Rzdigib3V0cHV0L3NlcS1mZWF0dXJlL2NhdXJpcy1yZW5hbWVkLWZhYXByZWQudHh0IiwgY29sX25hbWVzID0gYygibmFtZSIsImZhYS5zY29yZSIsImZhYS5wcmVkIiksIGNvbF90eXBlcyA9ICJjZGMiKSAlPiUgCiAgbXV0YXRlKGZhYS5wcmVkID0gaWZlbHNlKGZhYS5wcmVkID09ICJBZGhlc2luIiwgVFJVRSwgRkFMU0UpKQppZigiZnJ2LnNjb3JlIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1mcnYuc2NvcmUsIC1mcnYucHJlZCwgLWZhYS5zY29yZSwgLWZhYS5wcmVkKQpzZXFJbmZvIDwtIHNlcUluZm8gJT4lIGxlZnRfam9pbihmcnYpICU+JSBsZWZ0X2pvaW4oZmFhKQpzZXFJbmZvICU+JSAKICBncm91cF9ieShzcGVjaWVzX2lkLCBzdHJhaW4pICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgZnVuZ2FsUlYgPSBzdW0oZnJ2LnNjb3JlID4gMC41MTEpLCBmYWFwcmVkID0gc3VtKGZhYS5wcmVkLCBuYS5ybSA9IFQpLCAKICAgICAgICAgICAgYm90aCA9IHN1bShmcnYuc2NvcmUgPiAwLjUxMSAmIGZhYS5wcmVkKSkKYGBgCiMjIyBTaWduYWxQIGFuZCBHUEkgcHJlZGljdGlvbgpgYGB7ciBzaWduYWxQLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQojIFNpZ25hbCBwZXB0aWRlCmdmZi5uYW1lcyA8LSBjKCJpZCIsICJzb3VyY2UiLCAibmFtZSIsICJzdGFydCIsICJlbmQiLCAicHJvYiIsICJuYTEiLCAibmEyIiwgIm5hMyIpCnNpZ25hbHA1IDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtc2lnbmFscDUuZ2ZmMyIsIGNvbW1lbnQgPSAiIyIsIGNvbF9uYW1lcyA9IGdmZi5uYW1lcywgY29sX3R5cGVzID0gImNjY2lpZGNjYyIpCgppZigic2lnbmFscCIgJWluJSBuYW1lcyhzZXFJbmZvKSkKICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtc2lnbmFscCkKCnNlcUluZm8gPC0gbGVmdF9qb2luKHNlcUluZm8sIHNlbGVjdChzaWduYWxwNSwgbmFtZSA9IGlkLCBwcm9iKSwgYnkgPSBjKCJuYW1lIiA9ICJuYW1lIikpICU+JSAKICBtdXRhdGUoc2lnbmFscCA9ICFpcy5uYShwcm9iKSkgJT4lIHNlbGVjdCgtcHJvYikKYGBgCgpgYGB7ciBncGl9CnRtcCA8LSByZWFkX2RlbGltKCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtcHJlZGdwaS50eHQiLCBkZWxpbSA9ICJ8IiwgY29sX25hbWVzID0gYygibmFtZSIsImZwIiwib21lZ2EiKSkKcHJlZC5ncGkgPC0gdG1wICU+JSAgCiAgbXV0YXRlKG5hbWUgPSBzdHJfc3ViKG5hbWUsIDIsIC0yKSwgIyByZW1vdmUgPiBhbmQgdGhlIHRyYWlsaW5nIHNwYWNlCiAgICAgICAgIGZwID0gYXMubnVtZXJpYyhzdHJfc3ViKGZwLCA5LCAtMikpLCAjIGV4dHJhY3QgdGhlIG51bWVyaWMgcGFydAogICAgICAgICBpcy5ncGkgPSBmcCA8PSAwLjAxLCAgICAjIGJhc2VkIG9uIHRoZSBjdXRvZmYgb2YgdGhlIFByZWRHUEkgc2VydmVyIChwcm9iIDwgOTklIC0+IG5vdCBHUEktYW5jaG9yZWQpCiAgICAgICAgIG9tZWdhID0gc3RyX3N1YihvbWVnYSwgOCksCiAgICAgICAgIGNsZWF2ZVJlcyA9IHN0cl9zdWIob21lZ2EsIDEsIDEpLAogICAgICAgICBjbGVhdmVQb3MgPSBhcy5pbnRlZ2VyKHN0cl9zdWIob21lZ2EsIDMpKSwKICAgICAgICAgKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzZXFJbmZvLCBuYW1lLCBsZW5ndGgpLCBieSA9IGMoIm5hbWUiID0gIm5hbWUiKSkKCiMgcmVtb3ZlIHRoZSBjb2x1bW4gaWYgaXQgYWxyZWFkeSBleGlzdHMKaWYoInByZWQuZ3BpIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1wcmVkLmdwaSkKc2VxSW5mbyA8LSBsZWZ0X2pvaW4oc2VxSW5mbywgc2VsZWN0KHByZWQuZ3BpLCBuYW1lLCBwcmVkLmdwaSA9IGlzLmdwaSksIGJ5ID0gYygibmFtZSI9Im5hbWUiKSkKCnNlcUluZm8gJT4lIAogIGdyb3VwX2J5KHNwZWNpZXNfaWQsIHN0cmFpbikgJT4lIAogIHN1bW1hcml6ZShUb3RhbCA9IG4oKSwgU2lnbmFsUCA9IHN1bShzaWduYWxwKSwgR1BJX1ByZWQgPSBzdW0ocHJlZC5ncGkpLCBCb3RoID0gc3VtKHNpZ25hbHAgJiBwcmVkLmdwaSkpCgp3cml0ZV90c3Yoc2VxSW5mbywgIm91dHB1dC9zZXEtZmVhdHVyZS9SLXNlcWluZm8tdGFibGUudHN2IiwgY29sX25hbWVzID0gVFJVRSkKYGBgCgojIyMgRG9tYWluIGFyY2hpdGVjdHVyZQoKVGhlIGdvYWwgaXMgdG8gcHJvZHVjZSBhIGNhcnRvb24tbGlrZSBwbG90IGZvciBlYWNoIGhvbW9sb2cgb3V0bGluaW5nIHRoZWlyIG1haW4gZmVhdHVyZXMsIHN1Y2ggYXMgdGhlIGxvY2F0aW9ucyBvZiB0aGUgUEZhbSBkb21haW5zIChtYWlubHkgdGhlIEh5cF9yZWdfQ1dQKSwgbG9jYXRpb25zIG9mIHRoZSBzaWduYWwgcGVwdGlkZSBhbmQgR1BJLWFuY2hvciwgZGlzdHJpYnV0aW9uIG9mIFRBTkdPIHNlcXVlbmNlcy4gTm90ZSB0aGF0IGFsbCB0aGVzZSBmZWF0dXJlcyBjYW4gYmUgcmVwcmVzZW50ZWQgYXMgYSByYW5nZSB3aXRoIGFzc29jaWF0ZWQgbWV0YWRhdGEuIFNvIHRoZSBmaXJzdCBzdGVwIGlzIHRvIGNvbGxlY3QgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBmZWF0dXJlcwoKYGBge3J9CiMgR1BJLWFuY2hvcgojIHVzZSBwcmVkLmdwaQojIFBmYW0gZG9tYWlucwpwZmFtIDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtaG1tZXItc2Nhbi50eHQiLCBjb2xfdHlwZXMgPSAiY2lpaWljY2lpaWRkZGlpYyIpCiMgc2F2ZSBmZWF0dXJlIGZpbGUgZm9yIEphbHZpZXcgZXhhbWluYXRpb24KIyBwZmFtICU+JSBmaWx0ZXIoZ3JlcGwoIlhQXzAyODg4OTAzMyIsc2VxX2lkKSkgJT4lIHNlbGVjdChobW1fbmFtZSwgc2VxX2lkLCBlbnZlbG9wZV9zdGFydCwgZW52ZWxvcGVfZW5kKSAlPiUgbXV0YXRlKGZlYXR1cmV0eXBlID0gImRvbWFpbiIpICU+JSB3cml0ZV90c3YoIlhQXzAyODg4OTAzM19mZWF0dXJlcy5qYWx2aWV3IikKIyBJIG1hbnVhbGx5IGVkaXRlZCB0aGUgZmVhdHVyZSBmaWxlLCBzbyBJIGNvbW1lbnRlZCBvdXQgdGhlIGxpbmUgYWJvdmUgdG8gYXZvaWQgYWNjaWRlbnRhbGx5IAojIG92ZXJ3cml0aW5nIG15IG93biBlZGl0cwoKIyBmZWF0dXJlIHNldAojIHN0cnVjdHVyZTogaWQgIGZlYXR1cmUgIHN0YXJ0ICBlbmQKZmVhdHVyZSA8LSBiaW5kX3Jvd3MoCiAgc2VxSW5mbyAlPiUgbXV0YXRlKHR5cGUgPSAiZW50aXJlIHByb3RlaW4iLCBzdGFydCA9IDEpICU+JSBzZWxlY3QoaWQgPSBuYW1lLCB0eXBlLCBzdGFydCwgZW5kID0gbGVuZ3RoKSwKICBwZmFtICU+JSBzZWxlY3QoaWQgPSBzZXFfaWQsIHR5cGUgPSBobW1fbmFtZSwgc3RhcnQgPSBlbnZlbG9wZV9zdGFydCwgZW5kID0gZW52ZWxvcGVfZW5kKSwKICAjIGV4dGVuZCB0aGUgc2lnbmFsIHBlcHRpZGUgc2VnbWVudCBieSAxMCBhbWlubyBhY2lkcyB0byBtYWtlIGl0IG1vcmUgdmlzaWJsZQogIHNpZ25hbHA1ICU+JSBtdXRhdGUodHlwZSA9ICJTaWduYWxQIiwgZW5kID0gZW5kICsgMTApICU+JSBzZWxlY3QoaWQsIHR5cGUsIHN0YXJ0ID0gc3RhcnQsIGVuZCksCiAgIyBleHRlbmQgdGhlIEdQSS1hbmNob3IgQy10ZXJtaW51cyBzZWdtZW50IGJ5IDIwIGFtaW5vIGFjaWRzIHRvIG1ha2UgaXQgbW9yZSB2aXNpYmxlCiAgcHJlZC5ncGkgJT4lIGZpbHRlcihpcy5ncGkpICU+JSBtdXRhdGUodHlwZSA9ICJHUEktYW5jaG9yIiwgc3RhcnQgPSBjbGVhdmVQb3MtMTApICU+JSAKICAgIHNlbGVjdChpZCA9IG5hbWUsIHR5cGUsIHN0YXJ0LCBlbmQgPSBsZW5ndGgpCikKZmVhdHVyZSR0eXBlID0gb3JkZXJlZChmZWF0dXJlJHR5cGUsIGxldmVscyA9IGMoImVudGlyZSBwcm90ZWluIiwgIkh5cGhhbF9yZWdfQ1dQIiwgIkFzcCIsICJIeXIxIiwgIlNpZ25hbFAiLCAiR1BJLWFuY2hvciIpKQpmZWF0dXJlLmNvbG9ycyA8LSBjKCJncmV5IiwgIiMxZjc4YjQiLCAiI2IyZGY4YSIsICIjZmY3ZjAwIiwgIiNlMzFhMWMiLCAiIzZhM2Q5YSIpCiMgaW4gb3JkZXIgdG8gcGxvdCBwcm9wZXJ0aWVzIG9mIHRoZSBzZXF1ZW5jZXMgaW4gYW4gb3JkZXIgdGhhdCBpcyBjb25zaXN0ZW50IHdpdGggdGhlIHNlcXVlbmNlcycgcG9zaXRpb24gaW4gdGhlIGdlbmUgdHJlZQpnZW5ldHJlZU9yZGVyIDwtIHNjYW4oIm91dHB1dC9zZXEtZmVhdHVyZS9jYXVyaXMtcmVvcmRlci1ieS1nZW5lLXRyZWUudHh0Iiwgd2hhdCA9ICJjaGFyYWN0ZXIiKQpnZW5ldHJlZUNvbG9yIDwtIHRpYmJsZShuYW1lID0gZ2VuZXRyZWVPcmRlcikgJT4lIAogIG11dGF0ZShjb2xvciA9IGNhc2Vfd2hlbigKICAgIGdyZXBsKCJoYWVtdWxvbmkiLCBuYW1lKSB+ICIjMjU5NmJlNzAiLAogICAgZ3JlcGwoIjY2ODQiLCBuYW1lKSB+ICIjMGU4YzA3IiwKICAgIGdyZXBsKCJCODQ0MSIsIG5hbWUpIH4gIiMwZThjMDciLAogICAgZ3JlcGwoIkIxMTIyMCIsIG5hbWUpIH4gIiM3ODBhNzYiLAogICAgZ3JlcGwoIkIxMTIyMSIsIG5hbWUpIH4gIiMwNDA5ZmIiLAogICAgZ3JlcGwoIkIxMTI0MyIsIG5hbWUpIH4gIiNmZjRjMDAiLAogICAgVFJVRSB+ICIjMDAwMDAwIgogICAgKSkKZmVhdHVyZSRpZCA8LSBvcmRlcmVkKGZlYXR1cmUkaWQsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkKd3JpdGVfdHN2KGZlYXR1cmUsIGZpbGUgPSAib3V0cHV0L3NlcS1mZWF0dXJlL1ItZmVhdHVyZS10YWJsZS50c3YiLCBjb2xfbmFtZXMgPSBUUlVFKQpgYGAKCmBgYHtyIHBsb3RfZmVhdHVyZXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTksIHdhcm5pbmc9RkFMU0V9CnAgPC0gZ2dwbG90KGZlYXR1cmUsIGFlcyh4ID0gaWQsIHkgPSBzdGFydCkpICsgCiAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0gaWQsIHllbmQgPSBlbmQsIGNvbG9yID0gdHlwZSksIHNpemUgPSAyKQpwICsgY29vcmRfZmxpcCgpICsgdGhlbWVfY2xhc3NpYygpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGZlYXR1cmUuY29sb3JzKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9IHJldihnZW5ldHJlZUNvbG9yJGNvbG9yKSksCiAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuOCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsKICB5bGltKDEsIDQ1MDApICsgbGFicyh5ID0gIlBvc2l0aW9uIGluIHNlcXVlbmNlIiwgeCA9ICJTZXF1ZW5jZXMiLCBjb2xvciA9ICJEb21haW4gLyBGZWF0dXJlIikgKyAKICBnZ3RpdGxlKCJEb21haW4gYXJjaGl0ZWN0dXJlIikKZ2dzYXZlKCJvdXRwdXQvZmlndXJlLzIwMjEwNDI1LWhvbW9sb2dzLWRvbWFpbnMtc2NoZW1hdGljcy5wbmciLCBiZyA9ICJ0cmFuc3BhcmVudCIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikKYGBgCgojIyMgVEFOR08gcHJlZGljdGlvbiBvZiAkXGJldGEkLWFnZ3JlZ2F0aW9uIHByb25lIHNlcXVlbmNlcwoKVGhlIGFteWxvaWQtbGlrZSAkXGJldGEkLWFnZ3JlZ2F0aW9uIHByb25lIHNlcXVlbmNlcyBoYXZlIHRoZSBhYmlsaXR5IHRvIG1lZGlhdGUgc2VsZi1hZ2dyZWdhdGlvbiwgd2hpY2ggYm9vc3RzIHRoZSBsb2NhbCBjb25jZW50cmF0aW9uIG9mIHRoZSBhZGhlc2luIG1vbGVjdWxlcyBvbiB0aGUgY2VsbC1zdXJmYWNlLiBTaW1pbGFyIHRvIHRoZSBTL1QgZnJlcXVlbmN5IGFib3ZlLCB3ZSB3b3VsZCBsaWtlIHRvIHVzZSB0aGUgb3V0cHV0IGZyb20gdGhlIHByZWRpY3Rpb24gYWxnb3JpdGhtLCBUQU5HTywgdG8gdmlzdWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzdWNoIHNlcXVlbmNlIG1vdGlmcyBhbG9uZyB0aGUgbGVuZ3RoIG9mIHRoZSBYUF8wMjg4ODkwMzMgaG9tb2xvZyBzZXF1ZW5jZXMuCgojIyMjIFBhcnNlIHRhbmdvIG91dHB1dApgYGB7ciBleHRyYWN0X3RhbmdvX2luZm99CmV4dHJhY3RfdGFuZ28gPC0gZnVuY3Rpb24odGFuZ29fb3V0cHV0LCBhZ2dfdGhyZXNob2xkID0gNSwgcmVxdWlyZWRfaW5fc2VyaWFsID0gNSkgewogICAgcmVxdWlyZSh0aWR5dmVyc2UpCiAgICB0bXAgPC0gcmVhZF90c3YoZmlsZSA9IHRhbmdvX291dHB1dCwgY29sX3R5cGVzID0gImljZGRkZGQiKSAlPiUgCiAgICAgICAgIyBhIGJvb2xlYW4gdmVjdG9yIGZvciByZXNpZHVlcyBhYm92ZSB0aHJlc2hvbGQKICAgICAgICBtdXRhdGUocGFzcyA9IEFnZ3JlZ2F0aW9uID4gYWdnX3RocmVzaG9sZCkKICAgIHBhc3MucmxlIDwtIHJsZSh0bXAkcGFzcykgIyB0aGlzIGNyZWF0ZXMgYSBydW4gbGVuZ3RoIGVuY29kaW5nIHRoYXQgd2lsbCBiZSB1c2VmdWwgZm9yIGlkZW50aWZ5aW5nIHRoZSBzdWItc2VxdWVuY2VzIGluIGEgcnVuIGxvbmdlciB0aGFuIGNlcnRhaW4gbGVuZ3RoCiAgICAjIC0tLSBFeHBsYW5hdGlvbiAtLS0KICAgICMgdGhpcyBybGUgb2JqZWN0IGlzIGF0IHRoZSBjb3JlIG9mIHRoaXMgZnVuY3Rpb24KICAgICMgYW4gZXhhbXBsZSBvZiB0aGUgcmxlIGxvb2tzIGxpa2UKICAgICMgICBsZW5ndGhzOiBpbnRbMToxMF0gNSAxOSAyMCA4IDEgNSAxOSA2IDE4MSAxOAogICAgIyAgIHZhbHVlczogbG9naVsxOjEwXSBGIFQgIEYgIFQgRiBUIEYgIFQgRiAgIFQKICAgICMgICBub3RlIHRoYXQgYnkgZGVmaW5pdGlvbiB0aGUgdmFsdWVzIHdpbGwgYWx3YXlzIGJlIFQvRiBpbnRlcmRpZ2l0YXRlZAogICAgIyBvdXIgZ29hbCBpcyB0byBpZGVudGlmeSB0aGUgc3ViLXNlcXVlbmNlcyB0aGF0IGlzIGRlZmluZWQgYXMgYSBzdHJldGNoIG9mIAogICAgIyBuIGNvbnNlY3V0aXZlIHBvc2l0aW9ucyB3aXRoIGEgc2NvcmUgZ3JlYXRlciB0aGFuIHRoZSBjdXRvZmYgYW5kIHJlY29yZCB0aGUKICAgICMgc3ViLXNlcXVlbmNlLCBpdHMgbGVuZ3RoLCBzdGFydCBhbmQgZW5kIHBvc2l0aW9uLCA5MCUgcXVhbnRpbGUgb2YgdGhlIHNjb3JlCiAgICAjIC0tLSBFbmQgb2YgZXhwbGFuYXRpb24gLS0tCiAgICAjIDEuIGFzc2lnbnMgYSB1bmlxdWUgaWQgZm9yIGVhY2ggcnVuIG9mIGV2ZW50cwogICAgdG1wJGdyb3VwIDwtIHJlcCgxOmxlbmd0aChwYXNzLnJsZSRsZW5ndGhzKSwgdGltZXMgPSBwYXNzLnJsZSRsZW5ndGhzKQogICAgIyAyLiBleHRyYWN0IHRoZSBzdWJzZXF1ZW5jZXMKICAgIGFnZy5zZXEgPC0gdG1wICU+JSAKICAgICAgICBmaWx0ZXIocGFzcykgJT4lICMgZHJvcCByZXNpZHVlcyBub3QgcHJlZGljdGVkIHRvIGhhdmUgYWdncmVnYXRpb24gcG90ZW50aWFsCiAgICAgICAgZ3JvdXBfYnkoZ3JvdXApICU+JSAjIGNsdXN0ZXIgYnkgdGhlIHJ1bnMKICAgICAgICBzdW1tYXJpemUoc2VxID0gcGFzdGUwKGFhLCBjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgICAgc3RhcnQgPSBtaW4ocmVzKSwgZW5kID0gbWF4KHJlcyksIGxlbmd0aCA9IG4oKSwKICAgICAgICAgICAgICAgICAgbWVkaWFuID0gbWVkaWFuKEFnZ3JlZ2F0aW9uKSwKICAgICAgICAgICAgICAgICAgcTkwID0gcXVhbnRpbGUoQWdncmVnYXRpb24sIHByb2JzID0gMC45KSwKICAgICAgICAgICAgICAgICAgaXZ0ID0gc3VtKGFhICVpbiUgYygiSSIsIlYiLCJUIikpIC8gbGVuZ3RoKGFhKSwKICAgICAgICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogICAgICAgIG11dGF0ZShpbnRlcnZhbCA9IHN0YXJ0IC0gbGFnKGVuZCkgLSAxKSAlPiUgCiAgICAgICAgZmlsdGVyKGxlbmd0aCA+PSByZXF1aXJlZF9pbl9zZXJpYWwpICU+JSAKICAgICAgICBzZWxlY3QoLWdyb3VwKQogICAgcmV0dXJuKGFnZy5zZXEpCn0KYGBgCgpgYGB7ciBhcHBseX0KdGFuZ28ub3V0cHV0LmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICJvdXRwdXQvdGFuZ28iLCBwYXR0ZXJuID0gIi50eHR8LnR4dC5neiIsIGZ1bGwubmFtZXMgPSBUKQojIHRoZSByZWFkX2NzdigpIGZ1bmN0aW9uIHVzZWQgaW4gdGhlIGN1c3RvbSBmdW5jdGlvbiBjYW4gYXV0b21hdGljYWxseSBkZWNvbXByZXNzIGd6aXBwZWQgZmlsZXMKdGFuZ28ucmVzIDwtIGxhcHBseSh0YW5nby5vdXRwdXQuZmlsZXMsIGV4dHJhY3RfdGFuZ28pCm5hbWVzKHRhbmdvLnJlcykgPC0gZ3N1YigiLnR4dHwudHh0Lmd6IiwgIiIsIGJhc2VuYW1lKHRhbmdvLm91dHB1dC5maWxlcykpCiMgdG8gYWRkIHNwZWNpZXMgaW5mb3JtYXRpb24KdGFuZ28ucmVzLmRmIDwtIGJpbmRfcm93cyh0YW5nby5yZXMsIC5pZCA9ICJpZCIpICU+JQogIG11dGF0ZShpZCA9IGdzdWIoIl9CWzAtOV0rJCIsICIiLCBpZCkpCiMgc2F2ZSB0aGUgdGFuZ28gb3V0cHV0CndyaXRlX3Rzdih0YW5nby5yZXMuZGYsICJvdXRwdXQvdGFuZ28vdGFuZ29fc3VtbWFyeV90YWJsZS50c3YuZ3oiKQojIG11dGF0ZShzcGVjaWVzID0gc3RyX3NwbGl0KGlkLCAiXyg/IS4qXykiLCBzaW1wbGlmeSA9IFRSVUUpWywyXSkgCiMgZXh0cmFjdCB0aGUgc3BlY2llcyBuYW1lcwojIGNyZWRpdDogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjA0NTQ3NjgvaG93LXRvLXNwbGl0LWEtc3RyaW5nLWZyb20tcmlnaHQtdG8tbGVmdC1saWtlLXB5dGhvbnMtcnNwbGl0CiMgdGhlIHNwbGl0IHBhdHRlcm4gaXMgZXF1aXZhbGVudCB0byB0aGUgcnNwbGl0KCkgZnVuY3Rpb24gaW4gcHl0aG9uCmBgYAoKIyMjIyBQbG90dGluZyBUQU5HTyBoaXRzCmBgYHtyIHBsb3RfdGFuZ29fc2VxdWVuY2VzLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD05fQojIGFkZCBzcGVjaWVzIGFuZCBzdHJhaW4gaW5mb3JtYXRpb24gZm9yIHBsb3R0aW5nCnRhbmdvIDwtIGxlZnRfam9pbihzZWxlY3Qoc2VxSW5mbywgbmFtZSwgaWQsIHNwZWNpZXNfaWQsIHN0cmFpbiksICB0YW5nby5yZXMuZGYsIGJ5ID0gYygiaWQiID0gImlkIikpCiMgcmVvcmRlciB0aGUgc2VxdWVuY2VzIGZvciBwbG90dGluZwp0YW5nbyRuYW1lIDwtIG9yZGVyZWQodGFuZ28kbmFtZSwgbGV2ZWxzID0gcmV2KGdlbmV0cmVlT3JkZXIpKQojIHBsb3QKcDEgPC0gZ2dwbG90KGZpbHRlcihmZWF0dXJlLCB0eXBlID09ICJlbnRpcmUgcHJvdGVpbiIpLCBhZXMoeCA9IGlkLCB5ID0gc3RhcnQpKSArIAogIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGlkLCB5ZW5kID0gZW5kKSwgc2l6ZSA9IDIsIGNvbG9yID0gImdyZXk0MCIpCnAyIDwtIGdlb21fc2VnbWVudChkYXRhID0gdGFuZ28sIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsICB5ID0gaWZlbHNlKHN0YXJ0LTQgPj0gMCwgc3RhcnQtNCwgMCksIHllbmQgPSBlbmQgKyA0LCBjb2xvciA9IG1lZGlhbiksIHNpemUgPSAyKQpwMyA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IGZpbHRlcihmZWF0dXJlLCB0eXBlID09ICJIeXBoYWxfcmVnX0NXUCIpLCBhZXMoeCA9IGlkLCB5ID0gc3RhcnQsIHhlbmQgPSBpZCwgeWVuZCA9IGVuZCksIHNpemUgPSAyLCBjb2xvciA9ICIjMWY3OGI0IikKcDEgKyBwMiArIHAzICsgY29vcmRfZmxpcCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc2NhbGVfY29sb3JfZGlzdGlsbGVyKHR5cGUgPSAic2VxIiwgcGFsZXR0ZSA9IDE3LCBkaXJlY3Rpb24gPSAxKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9IHJldihnZW5ldHJlZUNvbG9yJGNvbG9yKSksCiAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuOCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsKICB5bGltKC0yLCA0NTAwKSArIGxhYnMoeSA9ICJQb3NpdGlvbiBpbiBzZXF1ZW5jZSIsIHggPSAiU2VxdWVuY2VzIiwgY29sb3IgPSAiTWVkaWFuIFRBTkdPIHNjb3JlIikgKyAKICBnZ3RpdGxlKCJUQU5HTyBoaXRzIHdpdGggSHlwaGFsX3JlZ19DV1AgZG9tYWluIG1hc2tlZCIpCmdnc2F2ZSgib3V0cHV0L2ZpZ3VyZS8yMDIxMDQyNS10YW5nby1zY29yZS1zZWdtZW50LnBuZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikKYGBgCgojIyMgVGFuZGVtIHJlcGVhdCBzdHJ1Y3R1cmVzCgpUaGUgbm9uLU5URCBwb3J0aW9uIG9mIHRoZSBwcm90ZWlucyBldm9sdmUgcmFwaWRseSBhbmQgbWFueSBvZiB0aGVtIGNvbnRhaW4gdGFuZGVtIHJlcGVhdHMuIFRoZXJlZm9yZSwgY2hhcmFjdGVyaXppbmcgYW5kIHZpc3VhbGl6aW5nIHRoZSB0eXBlLCBudW1iZXIgYW5kIHNwYXRpYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSB0YW5kZW0gcmVwZWF0cyBzZXJ2ZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzIGluIHRoZSBub24tTlREIHBhcnQgb2YgdGhlIHByb3RlaW5zIGluIHRoaXMgZmFtaWx5LgoKVG8gaWRlbnRpZnkgYW5kIGdyb3VwIHRhbmRlbSByZXBlYXRzLCBJIHVzZWQgW1hTVFJFQU1dKGh0dHBzOi8vYW1uZXdtYW5sYWIuc3RhbmZvcmQuZWR1L3hzdHJlYW0pIHdpdGggdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGBqYXZhIC1YbXgxMDAwbSAtWG1zMTAwMG0gLWphciB+L3N3L1hTVFJFQU0veHN0cmVhbS5qYXIgJGluIC1pLjcgLUkuNyAtZzMgLWUyIC1MMTUgLXogLUcgLU9gLiBUaGUgcGFyYW1ldGVycyB3ZXJlIGNob3NlbiB0byBpZGVudGlmeSBkZWdlbmVyYXRlIHRhbmRlbSByZXBlYXRzIHRoYXQgb2NjdXIgYXQgbGVhc3QgdHdvIHRpbWVzIGFuZCBtdXN0IGJlIGEgbWluaW11bSBsZW5ndGggb2YgNSBhLmEuIG9yIGxvbmdlciBhbmQgdGhlIG1pbmltdW0gbGVuZ3RoIG9mIGEgdGFuZGVtIHJlcGVhdCBkb21haW4gKD1wZXJpb2QgeCBjb3B5ICMpIG11c3QgYmUgZ3JlYXRlciB0aGFuIDE1IGEuYS4gUGxlYXNlIHNlZSBgc2NyaXB0L3hzdHJlYW0uc2hgIGZvciBleHBsYW5hdGlvbiBvZiB0aGUgcGFyYW1ldGVycy4KCmBgYHtyfQp0YW5kZW0gPC0gcmVhZF90c3YoIm91dHB1dC90YW5kZW0tcmVwZWF0cy9YU1RSRUFNX2NhdXJpc19vdXRncl9pMC43X2czX201X0wxNV9jaGFydC50c3YiLCAKICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9ICJjaWlpZmlkY2NjZCIpICU+JSAKICByZW5hbWUobmFtZSA9IGlkZW50aWZpZXIpICU+JSAKICBtdXRhdGUobmFtZSA9IG9yZGVyZWQobmFtZSwgbGV2ZWxzID0gcmV2KGdlbmV0cmVlT3JkZXIpKSkKIyBub3cgbGV0J3MgY3JlYXRlIGEgdGliYmxlIGZvciBwbG90dGluZywgd2hpY2ggd291bGQgY29udGFpbiBlYWNoIGluc3RhbmNlIG9mIHRoZSB0YW5kZW0gcmVwZWF0IG9uIGEgc2VwYXJhdGUgcm93CnRhbmRlbS5kaXYgPC0gdGFuZGVtICU+JSAKICByb3d3aXNlKG5hbWUpICU+JSAKICBzdW1tYXJpemUoZGl2ID0gbGlzdChjKHNlcShmcm9tID0gc3RhcnQsIHRvID0gZW5kLCBieSA9IHBlcmlvZCksIGVuZCkpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgdW5uZXN0KGRpdikKYGBgCgpgYGB7ciBwbG90X3RhbmRlbV9yZXBlYXRzLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05fQojIHBsb3QKcmVxdWlyZShSQ29sb3JCcmV3ZXIpCm4uY29sID0gbmxldmVscyh0YW5kZW0kdHlwZSkKdHIuY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpWzM6MTJdKShuLmNvbCkKcDEgPC0gZ2dwbG90KGZpbHRlcihmZWF0dXJlLCB0eXBlID09ICJlbnRpcmUgcHJvdGVpbiIpLCBhZXMoeCA9IGlkLCB5ID0gc3RhcnQpKSArIAogIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGlkLCB5ZW5kID0gZW5kKSwgc2l6ZSA9IDIuNSwgY29sb3IgPSAiZ3JleTQwIikKcDIgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSB0YW5kZW0sIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsICB5ID0gc3RhcnQsIHllbmQgPSBlbmQsIGNvbG9yID0gdHlwZSwgdGV4dCA9IGNvbnNlbnN1c19ub2dhcCksIHNpemUgPSAyLjUsIGFscGhhID0gMC45KQpwMyA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IHRhbmRlbS5kaXYsIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsIHkgPSBkaXYsIHllbmQgPSBkaXYgKyAyKSwgc2l6ZSA9IDIuNSkKcDQgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSBmaWx0ZXIoZmVhdHVyZSwgdHlwZSA9PSAiSHlwaGFsX3JlZ19DV1AiKSwgYWVzKHggPSBpZCwgeSA9IHN0YXJ0LCB4ZW5kID0gaWQsIHllbmQgPSBlbmQpLCBjb2xvciA9ICIjMWY3OGI0Iiwgc2l6ZSA9IDIuNSkKcCA8LSBwMSArIHAyICsgcDMgKyBwNCArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ci5jb2wpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gcmV2KGdlbmV0cmVlQ29sb3IkY29sb3IpKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuNSkpKSArCiAgeWxpbSgtMiwgNDUwMCkgKyBsYWJzKHkgPSAiUG9zaXRpb24gaW4gc2VxdWVuY2UiLCB4ID0gIlNlcXVlbmNlcyIsIGNvbG9yID0gIk1lZGlhbiBUQU5HTyBzY29yZSIpICsgCiAgZ2d0aXRsZSgiVGFuZGVtIHJlcGVhdCBkb21haW5zIHdpdGggSHlwaGFsX3JlZ19DV1AgZG9tYWluIHNob3duIikKcApnZ3NhdmUoIm91dHB1dC9maWd1cmUvMjAyMTA1MDYtdGFuZGVtLXJlcGVhdHMucG5nIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQpgYGAKKipOb3RlKiogQmx1ZSBib3hlcyBpbmRpY2F0ZSB0aGUgUEYxMTc2NSBkb21haW5zIHdoaWxlIGFsbCBvdGhlciBub24tZ3JleSBib3hlcyBpbmRpY2F0ZSBYU1RSRUFNLWRldGVybWluZWQgdGFuZGVtIHJlcGVhdCBkb21haW5zLiBDb2xvcnMgYXJlIHVzZWQgdG8gZ3JvdXAgaGlnaGx5IHNpbWlsYXIgdGFuZGVtIHJlcGVhdHMuIFRoZSBibGFjayB0aGluIGxpbmVzIGRlbWFyY2F0ZSBhZGphY2VudCB0YW5kZW0gcmVwZWF0IHVuaXRzLiBUaGUgdGFibGUgYmVsb3cgc2hvd3MgdGhlIGNvcHkgbnVtYmVyLCBwZXJpb2QgYW5kIGNvbnNlbnN1cyBzZXF1ZW5jZSBmb3IgZWFjaCB0YW5kZW0gZG9tYWluIG9yZ2FuaXplZCBieSB0aGUgaG9zdCBzZXF1ZW5jZXMuCgpgYGB7cn0KRFQ6OmRhdGF0YWJsZSgKICB0YW5kZW0gJT4lIAogICAgcmVuYW1lKHNlcUwgPSBzZXFMZW5ndGgsIGVyciA9IGNvbnNlbnN1c19lcnJvciwgc2VxID0gY29uc2Vuc3VzX25vZ2FwKSAlPiUgCiAgICBzZWxlY3QoLXNlcUFsaWduLCAtdHlwZSwgLWNvbnNlbnN1c19nYXAsIC1zZXEsIHNlcSkgJT4lIAogICAgYXJyYW5nZShkZXNjKG5hbWUpKSwKICBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkKKQpgYGAKCmBgYHtyIHRyYW5zZm9ybV90YW5kZW1fZmVhdHVyZV9kYXRhfQojIGNvbWJpbmUgc2VxdWVuY2UgZmVhdHVyZXMgd2l0aCB0YW5kZW0gcmVwZWF0cwp0ci5mZWF0dXJlIDwtIHJiaW5kKAogIGZlYXR1cmUgJT4lIAogICAgZmlsdGVyKHR5cGUgJWluJSBjKCJlbnRpcmUgcHJvdGVpbiIsICJIeXBoYWxfcmVnX0NXUCIpLCApICU+JQogICAgbXV0YXRlKG5hbWUgPSBpZCwgdGlwID0gaWZlbHNlKHR5cGUgPT0gImVudGlyZSBwcm90ZWluIiwgYXMuY2hhcmFjdGVyKG5hbWUpLCAiUEYxMTc2NSIpKSAlPiUgCiAgICBzZWxlY3QobmFtZSwgdHlwZSwgc3RhcnQsIGVuZCwgdGlwKSwKICB0YW5kZW0gJT4lIG11dGF0ZSh0eXBlID0gcGFzdGUwKCJ0YW5kZW0iLCB0eXBlKSkgJT4lIHNlbGVjdChuYW1lLCB0eXBlLCBzdGFydCwgZW5kLCB0aXAgPSBjb25zZW5zdXNfbm9nYXApCikgJT4lIG11dGF0ZSh0eXBlID0gZHJvcGxldmVscyh0eXBlKSkKYGBgCgpgYGB7ciBwbG90bHlfdGFuZGVtX3JlcGVhdHMsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTl9CiMgcGxvdApyZXF1aXJlKFJDb2xvckJyZXdlcikKcmVxdWlyZShwbG90bHkpCm4uY29sID0gbmxldmVscyh0ci5mZWF0dXJlJHR5cGUpCnRyLmNvbCA8LSBjKCJncmV5NDAiLCAiIzFmNzhiNCIsIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpWzM6MTJdKShuLmNvbC0yKSkKcDEgPC0gZ2dwbG90KHRyLmZlYXR1cmUsIGFlcyh4ID0gbmFtZSwgeSA9IHN0YXJ0LCB4ZW5kID0gbmFtZSwgeWVuZCA9IGVuZCwgY29sb3IgPSB0eXBlLCB0ZXh0ID0gdGlwKSkgKyAKICBnZW9tX3NlZ21lbnQoc2l6ZSA9IDIpCnAyIDwtIGdlb21fc2VnbWVudChzaXplID0gMiwgYWxwaGEgPSAwLjkpCnAgPC0gcDEgKyBwMiArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ci5jb2wpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gcmV2KGdlbmV0cmVlQ29sb3IkY29sb3IpKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuNSkpKSArCiAgeWxpbSgtMiwgNDUwMCkgKyBsYWJzKHkgPSAiUG9zaXRpb24gaW4gc2VxdWVuY2UiLCB4ID0gIlNlcXVlbmNlcyIsIGNvbG9yID0gIk1lZGlhbiBUQU5HTyBzY29yZSIpICsgCiAgZ2d0aXRsZSgiVGFuZGVtIHJlcGVhdCBkb21haW5zIHdpdGggSHlwaGFsX3JlZ19DV1AgZG9tYWluIHNob3duIikKZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikKYGBgCgo=